################################################################################
# BAREFOOT NETWORKS CONFIDENTIAL & PROPRIETARY
#
# Copyright (c) 2018-2019 Barefoot Networks, Inc.

# All Rights Reserved.
#
# NOTICE: All information contained herein is, and remains the property of
# Barefoot Networks, Inc. and its suppliers, if any. The intellectual and
# technical concepts contained herein are proprietary to Barefoot Networks,
# Inc.
# and its suppliers and may be covered by U.S. and Foreign Patents, patents in
# process, and are protected by trade secret or copyright law.
# Dissemination of this information or reproduction of this material is
# strictly forbidden unless prior written permission is obtained from
# Barefoot Networks, Inc.
#
# No warranty, explicit or implicit is provided, unless granted under a
# written agreement with Barefoot Networks, Inc.
#
# Milad Sharif (msharif@barefootnetworks.com)
#
###############################################################################

import logging

import ptf.testutils as testutils
from bfruntime_base_tests import BfRuntimeTest
import bfrt_grpc.bfruntime_pb2 as bfruntime_pb2

logger = logging.getLogger('Test')
logger.addHandler(logging.StreamHandler())

class ActionProfileTest(BfRuntimeTest):
    def runTest(self):
        ig_port = 1
        eg_ports = [2, 3, 4, 5]
        group_id = 1

        target = self.Target(device_id=0, pipe_id=0xffff)

        # Add the new member to the selection table.
        pkt = testutils.simple_tcp_packet()
        exp_pkt = pkt
        max_grp_size = 120

	'''
        self.insert_table_entry(
            target,
            'SwitchIngress.action_selector_sel',
            [self.KeyField('$SELECTOR_GROUP_ID', self.to_bytes(group_id, 4))],
            None,
            [self.DataField('$MAX_GROUP_SIZE', self.to_bytes(max_grp_size, 4))])
        '''

	members = ""
        for port in eg_ports:
            # Create a new member for each port with the port number as the id.
            self.insert_table_entry(
                target,
                'SwitchIngress.action_selector',
                [self.KeyField('$ACTION_MEMBER_ID', self.to_bytes(port, 4))],
                'SwitchIngress.hit',
                [self.DataField('port', self.to_bytes(port, 2))])

	    members += self.to_bytes(port, 4)

        #Add the new member to the selection table.
	# Adding all members at the same time along with the max group size
        self.insert_table_entry(
            target,
            'SwitchIngress.action_selector_sel',
            [self.KeyField('$SELECTOR_GROUP_ID', self.to_bytes(group_id, 4))],
            None,
	    [self.DataField('$MAX_GROUP_SIZE', self.to_bytes(max_grp_size, 4)), 
	     self.DataField('$ACTION_MEMBER_ID', members)])


        self.insert_table_entry(
            target,
            'SwitchIngress.forward',
            [self.KeyField('ig_intr_md.ingress_port', '\x00\x01')],
            None,
            [self.DataField('$SELECTOR_GROUP_ID', self.to_bytes(group_id, 4))])

	# Sleep for 5 seconds before sending the packet to ensure entry has been programmed
	# TODO: Call complete operations at the GRPC server before returning
	time.sleep(5)
        logger.info("Sending packet on port %d", ig_port)
        testutils.send_packet(self, ig_port, str(pkt))

        logger.info("Expecting packet on one of ports %s", eg_ports)
        testutils.verify_any_packet_any_port(self, [exp_pkt], eg_ports)

        self.delete_table_entry(
            target,
            'SwitchIngress.forward',
            [self.KeyField('ig_intr_md.ingress_port', '\x00\x01')])

	# Delete Selector Table entry
        logger.info("Deleting Selector group id %d", group_id)
        self.delete_table_entry(
            target,
            'SwitchIngress.action_selector_sel',
            [self.KeyField('$SELECTOR_GROUP_ID', self.to_bytes(group_id, 4))])

	# Delete Action profile members
        for port in eg_ports:
	    logger.info("Deleting Action profile member id %d", port)
            self.delete_table_entry(
                target,
                'SwitchIngress.action_selector',
                [self.KeyField('$ACTION_MEMBER_ID', self.to_bytes(port, 4))])

	# Sleep for 5 seconds before sending the packet to ensure entry has been programmed
	time.sleep(5)
        logger.info("Sending packet on port %d", ig_port)
        testutils.send_packet(self, ig_port, str(pkt))

        logger.info("Packet is expected to get dropped.")
        testutils.verify_no_other_packets(self)
